package com.fdhwws.web.servlet;

import com.fdh.myjdbcutil.JSONUtil;
import com.fdhwws.web.domain.User;
import com.fdhwws.web.entity.AjaxResult;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;

public abstract class BaseServlet extends HttpServlet {

    private final String REDIRECT = "redirect:";
    private final String FORWARD = "forward:";

    protected String redirect(String url) {
        return REDIRECT + url;
    }

    protected String forward(String url) {
        return FORWARD + url;
    }

    public static class HttpUtil {
        private final HttpServletRequest request;
        private final HttpServletResponse response;

        public HttpUtil(HttpServletRequest request, HttpServletResponse response) {
            this.request = request;
            this.response = response;
        }

        public HttpServletRequest getRequest() {
            return request;
        }

        public HttpServletResponse getResponse() {
            return response;
        }

        public String getParameter(String name) {
            return request.getParameter(name);
        }

        public Number getNumberParameter(String name) {
            String val = getParameter(name);
            return new Number() {
                @Override
                public int intValue() {
                    return Integer.parseInt(val);
                }

                @Override
                public long longValue() {
                    return Long.parseLong(val);
                }

                @Override
                public float floatValue() {
                    return Float.parseFloat(val);
                }

                @Override
                public double doubleValue() {
                    return Double.parseDouble(val);
                }
            };
        }

        public <T> T getAttribute(String name, Class<T> clazz) {
            return (T) request.getAttribute(name);
        }

        public void setAttribute(String name, Object value) {
            request.setAttribute(name, value);
        }

        public <T> T getJSONBody(Class<T> clazz) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, StandardCharsets.UTF_8);
                return JSONUtil.jsonToObject(json, clazz);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public <T> T getJSONBody(Class<T> clazz, Charset charset) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, charset);
                return JSONUtil.jsonToObject(json, clazz);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public <T> List<T> getJSONBodyList(Class<T> elementClass) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, StandardCharsets.UTF_8);
                return JSONUtil.jsonToListObject(json, elementClass);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public <T> List<T> getJSONBodyList(Class<T> elementClass, Charset charset) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, charset);
                return JSONUtil.jsonToListObject(json, elementClass);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public <T> Map<String, T> getJSONBodyMap(Class<T> valueClass) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, StandardCharsets.UTF_8);
                return JSONUtil.jsonToMapObject(json, valueClass);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public <T> Map<String, T> getJSONBodyMap(Class<T> valueClass, Charset charset) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, charset);
                return JSONUtil.jsonToMapObject(json, valueClass);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public Object getJsonBody(Type type) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, StandardCharsets.UTF_8);
                return JSONUtil.jsonToObject(json, type);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public Object getJsonBody(Type type, Charset charset) {
            try {
                ServletInputStream inputStream = request.getInputStream();
                byte[] bytes = inputStream.readAllBytes();
                String json = new String(bytes, charset);
                return JSONUtil.jsonToObject(json, type);
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
        }

        public void write(String content) {
            try {
                PrintWriter writer = response.getWriter();
                writer.write(content);
                writer.flush();
                writer.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    protected AjaxResult verifyUser(HttpUtil httpUtil) throws ServletException, IOException {
        User user = httpUtil.getAttribute("user", User.class);
        if (user == null) {
            return AjaxResult.error("请先登录", null);
        } else {
            return AjaxResult.success("成功", user);
        }
    }

    protected AjaxResult verifyAdminUser(HttpUtil httpUtil) throws ServletException, IOException {
        User user = httpUtil.getAttribute("user", User.class);
        if (user == null) {
            return AjaxResult.error("请先登录", null);
        } else if (!user.getAdmin()) {
            return AjaxResult.error("无权限", null);
        } else {
            return AjaxResult.success("成功", user);
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String requestURI = req.getRequestURI();
        String[] split = requestURI.split("/");
        if (split.length > 0) {
            String action = split[split.length - 1];
            try {
                HttpUtil httpUtil = new HttpUtil(req, resp);
                Method method = this.getClass().getMethod(action, HttpUtil.class);
                Object invoke = method.invoke(this, httpUtil);
                if (invoke == null) return;
                if (invoke instanceof String) {
                    String result = (String) invoke;
                    if (result.startsWith(REDIRECT)) {
                        resp.sendRedirect(result.split(":")[1]);
                    } else if (result.startsWith(FORWARD)) {
                        req.getRequestDispatcher(result.split(":")[1]).forward(req, resp);
                    } else {
                        httpUtil.write(result);
                    }
                } else {
                    //对象转换成json数据返回
                    String json = JSONUtil.objectToJson(invoke);
                    httpUtil.write(json);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
